﻿#region Copyright Notice
// 
// 
//  
//  Copyright (c) 2009-2011 Anindya Chatterjee
//  
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// 
// 
#endregion
using System;
using System.IO;
using System.Linq;

namespace AbstractClass.NPerf
{
    /// <summary>
    /// Represents a test result writer.
    /// </summary>
    public class ResultTracer
    {
        private readonly TextWriter _writer;

        /// <summary>
        /// Initializes a new instance of the <see cref="ResultTracer"/> class.
        /// </summary>
        public ResultTracer()
        {
            _writer = Console.Out;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ResultTracer"/> class.
        /// </summary>
        /// <param name="writer">The underlying writer.</param>
        public ResultTracer(TextWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException("writer");
            _writer = writer;
        }

        /// <summary>
        /// Attaches a test runner engine with the current writer.
        /// </summary>
        /// <param name="testRunner">The test runner.</param>
        /// <param name="writeEvents">Subscribes and writes events if set to <c>true</c>.</param>
        public void Attach(NPerfTestRunner testRunner, bool writeEvents)
        {
            if (testRunner == null)
                throw new ArgumentNullException("testRunner");

            if (writeEvents)
            {
                testRunner.TestSuiteStart += TesterTestSuiteStart;
                testRunner.TestSuiteEnd += TesterTestSuiteEnd;
                testRunner.TestUnitStart += TesterTestUnitStart;
                testRunner.TestUnitIgnored += TesterTestUnitIgnored;
                testRunner.TestUnitFailed += TesterTestUnitFailed;
                testRunner.TestUnitEnd += TesterTestUnitEnd;
            }

            testRunner.ResultWriter = this;
        }

        private void TesterTestUnitEnd(object sender, TestUnitRunEventArgs e)
        {
            _writer.WriteLine(LanguageResource.EndRun, e.TestUnit.Name);
        }

        private void TesterTestUnitFailed(object sender, TestFailedEventArgs e)
        {
            _writer.WriteLine(LanguageResource.FailedRun, e.FailedResult.Message);
        }

        private void TesterTestUnitIgnored(object sender, TestUnitRunEventArgs e)
        {
            _writer.WriteLine(LanguageResource.IgnoreTest, e.TestUnit.Name, e.TestUnit.IgnoredMessage);
        }

        private void TesterTestUnitStart(object sender, TestUnitRunEventArgs e)
        {
            _writer.WriteLine(LanguageResource.StartRun, e.TestUnit.Name);
            _writer.WriteLine(e.TestUnit.TestDescription);
        }

        private void TesterTestSuiteEnd(object sender, TestSuiteRunEventArgs e)
        {
            int ignored = e.TestSuite.IgnoredTests.Count;
            int failed = e.TestSuite.FailedResult.Count;
            int total = e.TestSuite.Tests.Count;
            _writer.WriteLine(LanguageResource.FinishTest, total - failed - ignored, ignored, failed);
        }

        private void TesterTestSuiteStart(object sender, TestSuiteRunEventArgs e)
        {
            _writer.WriteLine(LanguageResource.StartTest, e.TestSuite.TestFixture.Units.First().TestType.Name);
        }

        ///<summary>
        /// Writes out a formatted string and a new line.
        ///</summary>
        ///<param name="format">The formatting string.</param>
        ///<param name="args">The object array to write into the formatting string.</param>
        public void WriteLine(string format, params object[] args)
        {
            _writer.WriteLine(format, args);
        }

        ///<summary>
        /// Writes out a string message and a new line.
        ///</summary>
        ///<param name="msg">The message to write.</param>
        public void WriteLine(string msg)
        {
            _writer.WriteLine(msg);
        }

        ///<summary>
        /// Writes a line terminator.
        ///</summary>
        public void WriteLine()
        {
            _writer.WriteLine();
        }
    }
}